/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.apache.jena.graph.test;

import java.lang.reflect.*;

import junit.framework.*;
import org.apache.jena.graph.*;
import org.apache.jena.shared.*;

/**
 * MetaTestGraph
 */
public class MetaTestGraph extends AbstractTestGraph {
    protected final Class<? extends Graph> graphClass;

    public MetaTestGraph(Class<? extends Graph> graphClass, String name) {
        super(name);
        this.graphClass = graphClass;
    }

    public MetaTestGraph(String name) {
        super(name);
        graphClass = null;
    }

    /**
     * Construct a suite of tests from the test class <code>testClass</code> by
     * instantiating it three times, once each for the three reification styles, and
     * applying it to the graph <code>graphClass</code>.
     */
    public static TestSuite suite(Class<? extends Test> testClass, Class<? extends Graph> graphClass) {
        TestSuite result = new TestSuite();
        result.addTest(suiteX(testClass, graphClass));
        result.setName("Meta " + testClass.getName());
        return result;
    }

    public static TestSuite suiteX(Class<? extends Test> testClass, Class<? extends Graph> graphClass) {
        TestSuite result = new TestSuite();
        for ( Class<? > c = testClass ; Test.class.isAssignableFrom(c) ; c = c.getSuperclass() ) {
            Method[] methods = c.getDeclaredMethods();
            addTestMethods(result, testClass, methods, graphClass);
        }
        result.setName(testClass.getName());
        return result;
    }

    public static void addTestMethods(TestSuite result, Class<? extends Test> testClass, Method[] methods,
                                      Class<? extends Graph> graphClass) {
        for ( Method method : methods ) {
            if ( isPublicTestMethod(method) ) {
                result.addTest(makeTest(testClass, graphClass, method.getName()));
            }
        }
    }

    public static TestCase makeTest(Class<? extends Test> testClass, Class<? extends Graph> graphClass, String name) {
        Constructor<? > cons = getConstructor(testClass, new Class[]{Class.class, String.class});
        if ( cons == null )
            throw new JenaException("cannot find MetaTestGraph constructor");
        try {
            return (TestCase)cons.newInstance(new Object[]{graphClass, name});
        } catch (Exception e) {
            throw new JenaException(e);
        }
    }

    @Override
    public Graph getNewGraph() {
        return getGraph(this, graphClass);
    }

}
